//=============================================================================
//                              HsimMain.c
//=============================================================================
// AUTHOR      : XENER.COM | kjjeong
// DATE        : 2000.09.17
// DESCRIPTION : 
//=============================================================================
#define _HsimMain_c_

//=============================================================================
//                               I N C L U D E
//=============================================================================
#include	"HsimIncl.h"

#include "tst.hpp"


//=============================================================================
//                              C O N S T A N T
//=============================================================================

//=============================================================================
//                    C L A S S   A N D   S T R U C T U R E
//=============================================================================

//=============================================================================
//                               M A C R O
//=============================================================================

//=============================================================================
//                      S T A T I C   V A R I A B L E
//=============================================================================
#ifndef lint
char copyright[] = "\n\t@(#) Copyright (c) 2000, Xener Systems. All rights reserved.\n\n";
#endif

static void  SigHandler(SkSensorSig* sensor);

static char sccsid[64];

xc8		gSIG[256];
xui32	g_HsmbEntId;

CeEntity	*entity;
CeParams	*sendMsg;
SkWorld		*world;
SkWatcher	*wSensor;

xi32	instance_id = 0;
xi32	cliNum = 1;

xui32	myEntId, hsmbEntId;
xui32	mySysId, hsmbSysId;
xui32	myBlkId, hsmbBlkId;
xui32	myPortId, hsmbPortId;
xc8		myHostName[64], hsmbHostName[64];
xui32	oamHostSysID;
xui32	oamHostSysType;
xc8		oamHostSysName[64];

void	*g_tmAddr;

//=============================================================================
//                       S T A T I C   F U C T I O N
//=============================================================================
void sighandler(int signo);

static void SetComm();
static void SetPID(int argc, char **argv);
void ceEntityStateChanged(CeEntity *the, CeConn *conn, CeConnState state);
void handle_ChgSysNameMsg(CeMsg *msg, CeEntity *entity, CeConn *conn);
void TestGenSample();
void PorcessLoginID();

//=============================================================================
//                       M E S S A G E   D E F I N E
//=============================================================================
static CeMsgHandler  msgTable[] = {
	{(xc8 *)"UserInputStrEcho",	UserInputStrEcho,	1, handle_echosig},
	{(xc8 *)"WinCmdResp",			WinCmdResp,			1, handle_wincmdsig},
	{(xc8 *)"SystemMsg",			SystemMsg,			1, handle_SystemMsg},
	{(xc8 *)"ChgSysNameMsg",		ChgSysNameMsg,		1, handle_ChgSysNameMsg},

	{NULL, 0, 1, NULL}
};


main(int argc, char **argv)
{
	xi32	id, sec, msec, tod[7];

	if (argc < 2) {
		printf("\n\tUsage : %s Component_Name | \"localhost\" [port] or %s -Ver\n", argv[0], argv[0]);
		printf("\n\t >> example : hsim CompA 9102 or hsim CompA");
		printf("\n\t              hsim x.x.x.x 9102 or hsim x.x.x.x\n\n");
		exit(-1);
	}

	boost::thread agent_thread(init_agent);
	agent_thread.detach();

	if (!strcmp(argv[1], "-Ver")) {
		/* 
	 	 * Print Version Information 
		 */
		//printf("%s\n%s\n", version_release, version_time);
		exit(0);
	}

	printf("%s\n", copyright);
	gettime(&sec, &msec);
	GetDateTime(sec, &tod[0]);
	sprintf(sccsid, "\n\t@(#)HSIM 1.1 (Xener Systems) %04d/%02d/%02d. All rights reserved.\n\0", tod[1], tod[2], tod[3]);
	printf("%s\n", sccsid);

	strcpy(oamHostSysName, "MMC COMMAND\0");
	SetPID(argc, argv);
	world = new SkWorld(argc, argv);
    if (!SkWorld::init())  exit(1);
	
	sendMsg = new CeParams();
	// entity = new CeEntity(myEntId, mySysId, &SkWorld::eventTime, 12800, 3, 12800);
	entity = new CeEntity(myEntId, mySysId, 12800, 3, 12800);
    entity->method = ceEntityStateChanged;

	////// Call Back Funtion
	SetComm();

	////// CLI Registration
	wSensor = skWatcherEstablish();
	wSensor->mHandle = testHandle;
	wSensor->mAddWatcherCmd((xc8 *)"logout", testLogout, (xc8 *)"logout");
	wSensor->mAddWatcherCmd((xc8 *)"exit", testLogout, (xc8 *)"logout");
	wSensor->mAddWatcherCmd((xc8 *)"quit", testLogout, (xc8 *)"logout");
	wSensor->mAddWatcherCmd((xc8 *)"q", testLogout, (xc8 *)"logout");
	wSensor->mAddWatcherCmd((xc8 *)"load", testLoad, (xc8 *)"load");
	wSensor->mAddWatcherCmd((xc8 *)"stop", testStop, (xc8 *)"stop");

	///Signal Handlers for safe shutdown.   
	void*   userPtr = NULL;
	SkSensorSig  sigTerm(SigHandler, SIGTERM, NULL);
	SkWorld::sRegister(&sigTerm);

	SkSensorSig  sigSegv(SigHandler, SIGSEGV, NULL);
	SkWorld::sRegister(&sigSegv);

	SkSensorSig  sigInt(SigHandler, SIGINT, NULL);
	SkWorld::sRegister(&sigInt);

	SkSensorSig  sigBus(SigHandler, SIGBUS, NULL);
	SkWorld::sRegister(&sigBus);

	signal(SIGINT, sighandler);

	g_tmAddr = skTmOpen(10, 1, 10, 20);
    SkWorld::running = uTrue;

	fd_set		rdSet, wrSet, exSet;
	timeval		seltout;
	timeval		*seltoutPtr;
	int			rcvNum = 0;
	struct	timezone	tzp;
	static timeval  longto = { 1000000, 999999 };
	static timeval  noto   = { 0, 0 };
	static fd_set   nobits;

	memset((xc8 *)&nobits, 0x00, sizeof(nobits));
	while (SkWorld::running == uTrue) {
		rdSet = wrSet = exSet = nobits;
		seltout = longto;

		SkWorld::makeSelectRequest(&rdSet, &wrSet, &exSet, &seltout);
		seltoutPtr = (seltout == longto) ? (timeval *)0 : &seltout;

		rcvNum = select(FD_SETSIZE, &rdSet, &wrSet, &exSet, seltoutPtr);
		if (rcvNum < 0) {
			uLogApp(LOG_CRIT, "select rcvNum = -1(%s)", strerror(errno));
			if (errno != EINTR) {
				SkWorld::selectError(&rdSet, &wrSet, &exSet);
			}
			continue;
		}
		gettimeofday(&SkWorld::eventTime, &tzp);
		SkWorld::dispatchSensors(&rdSet, &wrSet, &exSet, &seltout);
    }
    SkWorld::cleanUp();
}

void handle_ChgSysNameMsg(CeMsg *msg, CeEntity *entity, CeConn *conn)
{
	OamSysInfo_M *sysInfo = (OamSysInfo_M *)msg->body;

	oamHostSysID = sysInfo->sysId;
	// after changing OamSysInfo_M structure, change this code 
	// sprintf(oamHostSysName, "%s", sysInfo->sysName);
    if (strcmp(sysInfo->sysName, sysInfo->compName) != 0) {
		switch (sysInfo->sysMode) {
		case HA_ACT_ALONE :
		case HA_ACTIVE :
			sprintf(oamHostSysName, "%s[ACT:%s]", sysInfo->compName, sysInfo->sysName); 
			break; 
		case HA_STANDBY :
		case HA_STBY_ALONE :
			sprintf(oamHostSysName, "%s[SBY:%s]", sysInfo->compName, sysInfo->sysName);
			break;
		case HA_UNKNOWN :
		default : 
			sprintf(oamHostSysName, "%s[UNK:%s]", sysInfo->compName, sysInfo->sysName); 
			break; 
		} 
	} else { 
		sprintf(oamHostSysName, "%s", sysInfo->sysName);
	} 
}

void ceEntityStateChanged(CeEntity *entity, CeConn *conn, CeConnState state)
{
    char strState[40];
	char strChoice[40];

    entity->getState(state, strState);
	entity->getChoice(conn->connChoice, strChoice);
	sprintf(errorData.string, "e,r(%d:%d), state(%s), choice(%s), H(%s), P(%d), fd(%d)\n",
        conn->localEntity->entId, conn->remoteEntId, strState, strChoice,
        conn->hostName, conn->portNum,conn->fd);
    uLogApp(LOG_DEB0, "======%s", errorData.string);

	g_HsmbEntId = conn->remoteEntId;

	switch (state) {
		case CeCONNECTED :
			handle_login(conn);
			break;
		case CeDESTROYED :
			printf("CLI Connection Closed\n");
			exit(0);
			break;
	}
}

static void SetComm()
{
	// for HA
	// entity->requestConnection(hsmbEntId, hsmbHostName, hsmbPortId);
	entity->requestConnection(hsmbEntId, hsmbHostName, hsmbPortId, SWC_mySysName);
	entity->registerMsgHandler(msgTable);
}

static void SetPID(int argc, char **argv)
{
	mySysId = 255;
	myBlkId = 0xfff8;
	myBlkId = getpid();
	myPortId = 9810;

	//hsmbSysId = atoi(argv[1]);
	hsmbSysId = 0;
	hsmbBlkId = 0x0002;
	strcpy(hsmbHostName, argv[1]);
	if (argc == 2) hsmbPortId = 9102;
	else           hsmbPortId = atoi(argv[2]);

	hsmbEntId = hsmbSysId << 24 | hsmbBlkId << 8;
	myEntId = mySysId << 24 | myBlkId << 8;
}

xi32 SendMsgProc(xui32 msgid, xc8 *msg, xui32 leng, xui32 Dest_ent)
{
    CeConn	*sconn = NULL;
    sendMsg->head.msgID 	= msgid;
    sendMsg->head.bodyLen 	= leng;
	memcpy(sendMsg->body, msg, leng);

    sconn = entity->getConn(Dest_ent);
	if (sconn != NULL && sconn->state == CeCONNECTED) {
		return (xi32)sconn->send(sendMsg, uFalse);
	} else {
		uLogApp(LOG_CRIT, "############################################", gSIG);
		uLogApp(LOG_CRIT, "##  getConn(%d) fail, msgid =  %d", Dest_ent, msgid);
		uLogApp(LOG_CRIT, "############################################", gSIG);
		return (-1);
	}
    return (1);
}

void SigHandler(SkSensorSig* sensor)
{
	ClientServerIPC     mmc;
	GUI_Login            guiLogin;
		   
	mmc.overflow = uFalse;          
	mmc.next     = uFalse;
	mmc.PacketNo = 1;
	mmc.usrType  = CLI_USER;
	mmc.dataType = LOGOUT;
	memset(guiLogin.UserName, 0, sizeof(guiLogin.UserName));
	memset(guiLogin.oldpasswd, 0, sizeof(guiLogin.oldpasswd));
	
	bcp(mmc.DataUnit, (xc8 *)&guiLogin, sizeof(GUI_Login));
	SendMsgProc(LoginLogout, (xc8 *) &mmc, sizeof(ClientServerIPC), g_HsmbEntId);
}

void sighandler(int signo)
{
	exit(0);
}
